package com.njcb.ams.web.advice;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.njcb.ams.pojo.bo.Head;
import com.njcb.ams.portal.SysBaseDefine;
import com.njcb.ams.factory.comm.DataBus;
import com.njcb.ams.support.exception.ExceptionUtil;
import com.njcb.ams.util.AmsJsonUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * mvc请求预处理，解析请求头信息,如数据字典、导出Excel等
 * 
 * @author liuyanlong
 *
 */
@Order(0)
@ControllerAdvice
public class AmsRequestBodyAdvice implements RequestBodyAdvice {
	private static final Logger logger = LoggerFactory.getLogger(AmsRequestBodyAdvice.class);

	@Autowired
	private ObjectMapper objectMapper;
	
	@Override
	public boolean supports(MethodParameter methodParameter, Type targetType,
			Class<? extends HttpMessageConverter<?>> converterType) {
		return true;
	}

	@Override
	public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
			Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
		return new CustomHttpInputMessage(inputMessage);
	}

	@Override
	public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
			Class<? extends HttpMessageConverter<?>> converterType) {
		return body;
	}

	@Override
	public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter,
			Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
		return body;
	}
	
	
	class CustomHttpInputMessage implements HttpInputMessage{
        private HttpInputMessage origin;

        public CustomHttpInputMessage(HttpInputMessage httpInputMessage) {
            this.origin = httpInputMessage;
        }

		@Override
        public InputStream getBody() throws IOException {
            HttpHeaders headers = origin.getHeaders();
            InputStream body = origin.getBody();

            // 空参，get 请求，流为空，非 application/json 请求，不处理参数
            MediaType contentType = headers.getContentType();
            if(contentType == null || body == null || !contentType.isCompatibleWith(MediaType.APPLICATION_JSON)){
            	return body;
            }
            String params = IOUtils.toString(body, "utf-8");
            
            logger.info("http request body: \n {}",params);
            if(StringUtils.isBlank(params)){
            	//body 被读取流后，要重新转化成流输出
            	return IOUtils.toInputStream(params, "UTF-8");
            }
            Map<String, Object> map = new HashMap<>();
            try{
                map = AmsJsonUtils.jsonToMap(params);
            } catch (Exception e) {
                logger.error("参数无法解析为json，忽略头处理" + e.getMessage());
                return IOUtils.toInputStream(params, "UTF-8");
            }
            Head head = new Head();
            //处理Head相关
            handleHead(head, map);
            //处理excel导出相关
            handleExport(head, map);
            DataBus.setObject(head);
            return IOUtils.toInputStream(params, "UTF-8");
        }

        @SuppressWarnings("unchecked")
		private void handleHead(Head head, Map<String, Object> map) throws IOException {
            Object headJson = map.get("head");
            if(null == headJson){
                return;
            }
            if(headJson instanceof Map){
                Map<String, Object> headMap = (Map<String, Object>) headJson;
                if(headMap.containsKey("dataDic")){
                    head.setDataDic((Map<String, List<String>>) headMap.get("dataDic"));
                }
                if(headMap.containsKey("model")){
                    head.setModel((String) headMap.get("model"));
                }
                if(headMap.containsKey("page")){
                    Object page = headMap.get("page");
                    if(page instanceof Integer){
                        head.setPage((Integer) page);
                    }else{
                        head.setPage(Integer.parseInt((String) page));
                    }
                }
                if(headMap.containsKey("rows")){
                    Object rows = headMap.get("rows");
                    if(rows instanceof Integer){
                        head.setRows((Integer) rows);
                    }else{
                        head.setRows(Integer.parseInt((String) rows));
                    }
                }
            }else if(headJson instanceof String){
                objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
                head = objectMapper.readValue(headJson.toString(), Head.class);
            }
        }

        @SuppressWarnings("unchecked")
		private void handleExport(Head head, Map<String, Object> param) {
            if(SysBaseDefine.QUERY_MODEL_EXPALL.equals(head.getModel())){
                Object colTitle = param.get("columnTitle");
                Object colValue = param.get("columnValue");
                if(colTitle instanceof ArrayList && colValue instanceof ArrayList){
                    head.setColumnTitle((ArrayList<String>)colTitle);
                    head.setColumnValue((ArrayList<String>)colValue);
                }else{
                    ExceptionUtil.throwAppException("报文头head中columnTitle或columnValue字段格式不正确");
                }
            }
        }

        @Override
        public HttpHeaders getHeaders() {
            return origin.getHeaders();
        }

    }

}
